﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using Microsoft.Practices.Composite.Events;
using Microsoft.Practices.Composite.Presentation.Commands;
using StockholmsStad.Windows.UI.Infrastructure.Properties;
using System.Collections.ObjectModel;
using StockholmsStad.Windows.UI.Infrastructure.ValidationRules;
using StockholmsStad.Windows.UI.Modules.Minister.BusinessEntities;

namespace StockholmsStad.Windows.UI.Modules.Minister.Models
{
    public class MinisterPresentationModel : IDataErrorInfo, INotifyPropertyChanged
    {
        private readonly IDictionary<string, string> errors = new Dictionary<string, string>();

        public event EventHandler<DataEventArgs<MinisterPresentationModel>> Saved;
        public event EventHandler<DataEventArgs<MinisterPresentationModel>> PrintedMinisterRegister;
        public event EventHandler<DataEventArgs<MinisterPresentationModel>> PrintedMinisterReimbursement;
        public event EventHandler<DataEventArgs<MinisterPresentationModel>> PrintedMinisterService;

        public DelegateCommand<object> SaveCommand { get; private set; }
        public DelegateCommand<object> PrintMinisterRegisterCommand { get; private set; }
        public DelegateCommand<object> PrintMinisterReimbursementCommand { get; private set; }
        public DelegateCommand<object> PrintMinisterServiceCommand { get; private set; }

        #region Properties

        public bool HasMinisterServices { get; set; }

        private int? ministerId;
        public int? MinisterId
        {
            get
            {
                return ministerId;
            }
            set
            {
                if (!value.Equals(ministerId))
                {
                    ministerId = value;
                    PropertyChanged(this, new PropertyChangedEventArgs("MinisterId"));
                }
            }
        }

        public string IsSpecialAssignment
        {
            get { return SpecialAssignment ? "Ja" : ""; }
        }

        private string ministerCode;
        public string MinisterCode
        {
            get
            {
                return ministerCode;
            }
            set
            {
                if (!value.Equals(ministerCode))
                {
                    ministerCode = value;
                    PropertyChanged(this, new PropertyChangedEventArgs("MinisterCode"));
                }
            }
        }

        private DateTime? assignmentStartDate;
        public DateTime? AssignmentStartDate
        {
            get
            {
                return assignmentStartDate;
            }
            set
            {
                if (!value.Equals(assignmentStartDate))
                {
                    assignmentStartDate = value;
                    PropertyChanged(this, new PropertyChangedEventArgs("AssignmentStartDate"));
                }
            }
        }

        private DateTime? assignmentEndDate;
        public DateTime? AssignmentEndDate
        {
            get
            {
                return assignmentEndDate;
            }
            set
            {
                if (!value.Equals(assignmentEndDate))
                {
                    assignmentEndDate = value;
                    PropertyChanged(this, new PropertyChangedEventArgs("AssignmentEndDate"));
                }
            }
        }

        private bool specialAssignment;
        public bool SpecialAssignment
        {
            get
            {
                return specialAssignment;
            }
            set
            {
                if (!value.Equals(specialAssignment))
                {
                    specialAssignment = value;
                    PropertyChanged(this, new PropertyChangedEventArgs("SpecialAssignment"));
                }
            }
        }

        public string FullName
        {
            get { return string.Format("{0} {1}", FirstName, LastName); }
        }

        private string firstName;
        public string FirstName
        {
            get
            {
                return firstName;
            }
            set
            {
                if (!value.Equals(firstName))
                {
                    firstName = value;
                    PropertyChanged(this, new PropertyChangedEventArgs("FirstName"));
                }
            }
        }

        private string lastName;
        public string LastName
        {
            get
            {
                return lastName;
            }
            set
            {
                if (!value.Equals(lastName))
                {
                    lastName = value;
                    PropertyChanged(this, new PropertyChangedEventArgs("LastName"));
                }
            }
        }

        private string birthdayNumber;
        public string BirthdayNumber
        {
            get
            {
                return birthdayNumber;
            }
            set
            {
                if (!value.Equals(birthdayNumber))
                {
                    birthdayNumber = value;
                    PropertyChanged(this, new PropertyChangedEventArgs("BirthdayNumber"));
                }
            }
        }

        private string coAddress;
        public string CoAddress
        {
            get
            {
                return coAddress;
            }
            set
            {
                if (!value.Equals(coAddress))
                {
                    coAddress = value;
                    PropertyChanged(this, new PropertyChangedEventArgs("CoAddress"));
                }
            }
        }

        private string streetAddress;
        public string StreetAddress
        {
            get
            {
                return streetAddress;
            }
            set
            {
                if (!value.Equals(streetAddress))
                {
                    streetAddress = value;
                    PropertyChanged(this, new PropertyChangedEventArgs("StreetAddress"));
                }
            }
        }

        private string zipCode;
        public string ZipCode
        {
            get
            {
                return zipCode;
            }
            set
            {
                if (!value.Equals(zipCode))
                {
                    zipCode = value;
                    PropertyChanged(this, new PropertyChangedEventArgs("ZipCode"));
                }
            }
        }

        private string city;
        public string City
        {
            get
            {
                return city;
            }
            set
            {
                if (!value.Equals(city))
                {
                    city = value;
                    PropertyChanged(this, new PropertyChangedEventArgs("City"));
                }
            }
        }

        private string country;
        public string Country
        {
            get
            {
                return country;
            }
            set
            {
                if (!value.Equals(country))
                {
                    country = value;
                    PropertyChanged(this, new PropertyChangedEventArgs("Country"));
                }
            }
        }

        private string email;
        public string Email
        {
            get
            {
                return email;
            }
            set
            {
                if (!value.Equals(email))
                {
                    email = value;
                    PropertyChanged(this, new PropertyChangedEventArgs("Email"));
                }
            }
        }

        private string phoneNumber;
        public string PhoneNumber
        {
            get
            {
                return phoneNumber;
            }
            set
            {
                if (!value.Equals(phoneNumber))
                {
                    phoneNumber = value;
                    PropertyChanged(this, new PropertyChangedEventArgs("PhoneNumber"));
                }
            }
        }

        private string cellPhone;
        public string CellPhone
        {
            get
            {
                return cellPhone;
            }
            set
            {
                if (!value.Equals(cellPhone))
                {
                    cellPhone = value;
                    PropertyChanged(this, new PropertyChangedEventArgs("CellPhone"));
                }
            }
        }

        private string note;
        public string Note
        {
            get
            {
                return note;
            }
            set
            {
                if (!value.Equals(note))
                {
                    note = value;
                    PropertyChanged(this, new PropertyChangedEventArgs("Note"));
                }
            }
        }

        private DateTime? reimbursementDate;
        public DateTime? ReimbursementDate
        {
            get
            {
                return reimbursementDate;
            }
            set
            {
                if (!value.Equals(reimbursementDate))
                {
                    reimbursementDate = value;
                    PropertyChanged(this, new PropertyChangedEventArgs("ReimbursementDate"));
                }
            }
        }

        private ObservableCollection<string> languages;
        public ObservableCollection<string> Languages
        {
            get
            {
                return languages;
            }
            set
            {
                if (!value.Equals(languages))
                {
                    languages = value;
                    PropertyChanged(this, new PropertyChangedEventArgs("Languages"));
                }
            }
        }

        public MinisterServiceList MinisterServiceList { get; set; }

        #endregion

        #region ErrorHandling and Validation

        public string this[string columnName]
        {
            get
            {
                if (errors.ContainsKey(columnName))
                    return errors[columnName];

                return null;
            }
            set
            {
                errors[columnName] = value;
            }
        }

        private void ClearError(string columnName)
        {
            if (errors.ContainsKey(columnName))
                errors.Remove(columnName);
        }

        private void Validate()
        {
            if (string.IsNullOrEmpty(FirstName))
            {
                this["FirstName"] = Resources.InvalidFirstName;
            }
            else
            {
                ClearError("FirstName");
            }

            if (string.IsNullOrEmpty(LastName))
            {
                this["LastName"] = Resources.InvalidLastName;
            }
            else
            {
                ClearError("LastName");
            }

            if (string.IsNullOrEmpty(StreetAddress))
            {
                this["StreetAddress"] = Resources.AddressMustBeProvided;
            }
            else
            {
                ClearError("StreetAddress");
            }

            if (string.IsNullOrEmpty(ZipCode))
            {
                this["ZipCode"] = Resources.ZipCodeMustBeProvided;
            }
            else
            {
                ClearError("ZipCode");
            }

            if (string.IsNullOrEmpty(Email))
            {
                this["Email"] = Resources.EmailMustBeProvided;
            }
            else
            {
                if(EmailAddressValidationRule.IsValidEmail(Email))
                    ClearError("Email");
                else
                    this["Email"] = Resources.InvalidEmailAddress;
            }


            if (string.IsNullOrEmpty(City))
            {
                this["City"] = Resources.CityMustBeProvided;
            }
            else
            {
                ClearError("City");
            }

            if (string.IsNullOrEmpty(MinisterCode))
            {
                this["MinisterCode"] = Resources.InvalidMinisterCode;
            }
            else
            {
                ClearError("MinisterCode");
            }

            CheckBirthdayNumberForValidity();
        }

        private void CheckBirthdayNumberForValidity()
        {
            if (string.IsNullOrEmpty(BirthdayNumber))
            {
                this["BirthdayNumber"] = Resources.BirthdayMustBeProvided;
            }
            else
            {
                string errorMessage;
                if (PersonalNumberValidationRule.IsValidBirthdayNumber(BirthdayNumber,
                    true, out errorMessage))
                {
                    ClearError("BirthdayNumber");
                }
                else
                {
                    this["BirthdayNumber"] = errorMessage;
                }
            }
        }


        #endregion

        #region Contructor
        public MinisterPresentationModel()
        {
            SaveCommand = new DelegateCommand<object>(Save, CanSave);
            PrintMinisterRegisterCommand = new DelegateCommand<object>(PrintMinisterRegister);
            PrintMinisterReimbursementCommand = new DelegateCommand<object>(PrintMinisterReimbursement);
            PrintMinisterServiceCommand = new DelegateCommand<object>(PrintMinisterService);

            PropertyChanged += OnPropertyChangedEvent;
            Validate();
        }
        #endregion

        private void OnPropertyChangedEvent(object sender, PropertyChangedEventArgs e)
        {
            Validate();

            SaveCommand.RaiseCanExecuteChanged();
        }

        private bool CanSave(object obj)
        {
            return errors.Count == 0 && AssignmentStartDate.HasValue && AssignmentEndDate.HasValue;
        }

        private void Save(object obj)
        {
            if (CanSave(obj))
                OnSaved(new DataEventArgs<MinisterPresentationModel>(this));
        }

        private void PrintMinisterRegister(object obj)
        {
            OnPrintMinisterRegister(new DataEventArgs<MinisterPresentationModel>(this));
        }

        private void PrintMinisterReimbursement(object obj)
        {
            OnPrintMinisterReimbursement(new DataEventArgs<MinisterPresentationModel>(this));
        }

        private void PrintMinisterService(object obj)
        {
            OnPrintMinisterService(new DataEventArgs<MinisterPresentationModel>(this));
        }

        private void OnSaved(DataEventArgs<MinisterPresentationModel> e)
        {
            var savedHandler = Saved;

            if (savedHandler != null)
                savedHandler(this, e);
        }

        private void OnPrintMinisterRegister(DataEventArgs<MinisterPresentationModel> e)
        {
            var printHandler = PrintedMinisterRegister;

            if (printHandler != null)
                printHandler(this, e);
        }

        private void OnPrintMinisterReimbursement(DataEventArgs<MinisterPresentationModel> e)
        {
            var printHandler = PrintedMinisterReimbursement;

            if (printHandler != null)
                printHandler(this, e);
        }

        private void OnPrintMinisterService(DataEventArgs<MinisterPresentationModel> e)
        {
            var printHandler = PrintedMinisterService;

            if (printHandler != null)
                printHandler(this, e);
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        #region IDataErrorInfo Members

        public string Error
        {
            get
            {
                // Inte implementerad, då vi inte använder denna, vi visar fel på varje kontroll istället.
                throw new NotImplementedException();
            }
        }

        #endregion
    }
}
